using System;
using Combat;
using Locomotion;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;

namespace Controls
{
    public class PlayerController : MonoBehaviour
    {
        public enum ControlType
        {
            Gameplay,
            UI
        };
        
        public event Action MovePerformed; 
        public event Action ShootPerformed;
        public event Action MenuPerformed;
        
        private GameControls _controls;

        private Mover _mover;
        private Shooter _shooter;
        private WeaponSwitch _weaponSwitch;

        private Vector2 _input;

        private Camera _mainCamera;
        
        
        private void Awake()
        {
            _controls = new GameControls();
            _controls.GamePlay.Move.performed += cxt => MovePerformed?.Invoke();
            _controls.GamePlay.Shoot.performed += cxt => ShootPerformed?.Invoke();
            _controls.GamePlay.SwitchWeapon0.performed += SwitchWeapon0_performed;
            _controls.GamePlay.SwitchWeapon1.performed += SwitchWeapon1_performed;
            _controls.GamePlay.SwitchWeapon2.performed += SwitchWeapon2_performed;
            _controls.GamePlay.SwitchWeapon3.performed += SwitchWeapon3_performed;
            _controls.GamePlay.Menu.performed += Menu_Performed;
            _controls.UI.Resume.performed += Menu_Performed;
            
            _mover = GetComponent<Mover>();
            _shooter = GetComponent<Shooter>();
            _weaponSwitch = GetComponent<WeaponSwitch>();

            _mainCamera = Camera.main;
        }

        private void Start()
        {
            SwitchControl(ControlType.Gameplay);
        }

        private void Update()
        {
            HandleMoveInput();
            HandleAimInput();
            HandleShootInput();
            HandleSwitchWeaponInput();
        }

        public void SwitchControl(ControlType controlType)
        {
            switch (controlType)
            {
                case ControlType.Gameplay:
                    _controls.GamePlay.Enable();
                    _controls.UI.Disable();
                    break;
                case ControlType.UI:
                    _controls.GamePlay.Disable();
                    _controls.UI.Enable();
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(controlType), controlType, null);
            }
        }

        public Vector3 GetMouseWorldPosition()
        {
            return GetWorldPosition(_controls.GamePlay.AimCursor.ReadValue<Vector2>());
        }

        private void Menu_Performed(InputAction.CallbackContext obj)
        {
            MenuPerformed?.Invoke();
        }
        
        private void SwitchWeapon0_performed(InputAction.CallbackContext obj)
        {
            SwitchWeapon(0);
        }
        
        private void SwitchWeapon1_performed(InputAction.CallbackContext obj)
        {
            SwitchWeapon(1);
        }
        
        private void SwitchWeapon2_performed(InputAction.CallbackContext obj)
        {
            SwitchWeapon(2);
        }
        
        private void SwitchWeapon3_performed(InputAction.CallbackContext obj)
        {
            SwitchWeapon(3);
        }

        private void HandleMoveInput()
        {
            _input = _controls.GamePlay.Move.ReadValue<Vector2>();

            _mover.Move(_input);
        }

        private void HandleAimInput()
        {
            if (Gamepad.current is not null)
            {
                Vector3 aimDirection = _controls.GamePlay.Aim.ReadValue<Vector2>();
                
                if (aimDirection != Vector3.zero)
                {
                    _shooter.AimAtDirection(aimDirection);
                    return;
                }
            }
            
            Vector3 aimPosition = GetMouseWorldPosition();
            _shooter.AimAtPosition(aimPosition);
        }

        private void HandleShootInput()
        {
            if (EventSystem.current.IsPointerOverGameObject())
            {
                return;
            }

            if (_controls.GamePlay.Shoot.IsPressed())
            {
                _shooter.Shoot();
            }
        }
        
        private void HandleSwitchWeaponInput()
        {
            float scrollY = _controls.GamePlay.ScrollSwitchWeapon.ReadValue<float>();
            if (scrollY == 0)
            {
                return;
            }
            
            if (scrollY > 0)
            {
                _weaponSwitch.PreviousWeapon();
            }
            else
            {
                _weaponSwitch.NextWeapon();
            }
        }

        private void SwitchWeapon(int index)
        {
            _weaponSwitch.SwitchWeapon(index);
        }

        private Vector3 GetWorldPosition(Vector2 screenPosition)
        {
            Vector3 worldPosition = _mainCamera.ScreenToWorldPoint(screenPosition);
            worldPosition.z = 0f;
            return worldPosition;
        }
    }
}
